package com.landian.commons.jpa.reposiotry;

import com.google.common.collect.Lists;
import com.landian.commons.base.hql.Searchable;
import com.landian.commons.jpa.builder.PageRequestBuilder;
import com.landian.commons.jpa.builder.PredicateFactory;
import com.landian.commons.jpa.builder.SortBuilder;
import com.landian.commons.jpa.builder.SortBuilderRef;
import com.landian.commons.jpa.converter.PredicableConverter;
import com.landian.commons.jpa.criteria.EmptySearchable;
import com.landian.commons.jpa.criteria.Predicable;
import com.landian.commons.jpa.criteria.PredicableContainer;
import com.landian.commons.jpa.criteria.PredicableFactory;
import com.landian.commons.jpa.hql.*;
import com.landian.commons.jpa.order.*;
import com.landian.commons.jpa.update.UpdateUnit;
import com.landian.commons.jpa.update.UpdateUnitContainer;
import com.landian.commons.jpa.utils.PathUtils;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.data.domain.*;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.Tuple;
import javax.persistence.criteria.*;
import javax.persistence.criteria.Order;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

import static java.util.stream.Collectors.toList;

/**
 *
 * @author caojl
 * @create 2017/11/29
 * to be continue
 **/
public class BaseRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T,ID>
        implements BaseRepository<T,ID>, JpaSpecificationExecutor<T> {

    private final EntityManager entityManager;

	/**
	 * 父类没有不带参数的构造方法，这里手动构造父类
	 * @param domainClass
	 * @param entityManager
	 */
    public BaseRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
        super(domainClass, entityManager);
        this.entityManager = entityManager;
    }

	private Predicate getIdPredicate(CriteriaBuilder criteriaBuilder, String id, Path idPathTarget) {
		return criteriaBuilder.equal(idPathTarget, id);
	}

	@Override
	public long count(Predicable... predicable) {
		Specification<T> spec = buildSpecification(predicable);
		return count(spec);
	}

	@Override
	public long count(Searchable searchable, Predicable... predicable) {
		Specification<T> spec = buildSpecification(searchable, predicable);
		return count(spec);
	}

	@Override
	public boolean exists(Predicable... predicable) {
		long count = count(predicable);
		if(count > 0){
			return true;
		}
		return false;
	}

	/**
	 * // TODO 后期优化为空对象
	 * @return
	 */
	private Predicable[] getEmptyPredicable(){
		Predicable[] predicable = {};
		return predicable;
	}

	@Override
	public List<T> findTop(int size) {
		PageRequest pageRequest = PageRequestBuilder.newInstance(0, size);
		Page<T> page = findPage(pageRequest, getEmptyPredicable());
		return page.getContent();
	}

	@Override
	public List<T> findTop(int size, com.landian.commons.jpa.order.Order... orders) {
		Sort sort = SortBuilderRef.build(orders);
		PageRequest pageRequest = PageRequestBuilder.newInstance(0, size, sort);
		Page<T> page = findPage(EmptySearchable.newInstance(), pageRequest);
		return page.getContent();
	}

	@Override
	public List<T> findTop(int size, com.landian.commons.jpa.order.Sort sortSrc, Predicable... predicable) {
		Sort sort = SortBuilderRef.build(sortSrc);
		PageRequest pageRequest = PageRequestBuilder.newInstance(0, size, sort);
		Page<T> page = findPage(pageRequest, predicable);
		return page.getContent();
	}

	@Override
	public List<T> findList(Predicable... predicable) {
		Specification<T> spec = buildSpecification(predicable);
		return findAll(spec);
	}

	@Override
	public List<T> findList(com.landian.commons.jpa.order.Order... orders) {
		return findAll(SortBuilderRef.build(orders));
	}

	@Override
	public List<T> findList(Predicable predicable, Sort sort) {
		return findList(sort, predicable);
	}

	@Override
	public List<T> findList(Predicable predicable, com.landian.commons.jpa.order.Sort sortSrc) {
		return findList(SortBuilderRef.build(sortSrc), predicable);
	}

	@Override
	public List<T> findList(Predicable predicable, OrderUnit orderUnit) {
		return findList(orderUnit, predicable);
	}

	@Override
	public List<T> findList(Predicable predicable, com.landian.commons.jpa.order.Order order) {
		return findList(order, predicable);
	}

	@Override
	public List<T> findList(List<Predicable> predicableList) {
		Predicable[] predicableArr = null;
		if(CollectionUtils.isNotEmpty(predicableList)){
			predicableArr = predicableList.toArray(new Predicable[]{});
		}
		return findList(predicableArr);
	}

	@Override
	public List<T> findList(Sort sort, Predicable... predicable) {
		Specification<T> spec = buildSpecification(predicable);
		if(null == sort){
			return findAll(spec);
		}
		return findAll(spec,sort);
	}

	@Override
	public List<T> findList(OrderUnit orderUnit, Predicable... predicable) {
		Specification<T> spec = buildSpecification(predicable);
		if(null == orderUnit){
			return findAll(spec);
		}
		Sort sort = SortBuilder.build(orderUnit);
		return findAll(spec, sort);
	}

	@Override
	public List<T> findList(com.landian.commons.jpa.order.Order order, Predicable... predicable) {
		Specification<T> spec = buildSpecification(predicable);
		if(null == order){
			return findAll(spec);
		}
		Sort sort = SortBuilderRef.build(order);
		return findAll(spec, sort);
	}

	@Override
	public List<T> findList(Searchable searchVo) {
		Specification<T> spec = buildSpecification(searchVo, null);
		return findAll(spec);
	}

	@Override
	public List<T> findList(Searchable searchable, OrderUnit... orderUnit) {
		Sort sort = SortBuilder.build(orderUnit);
		Specification<T> spec = buildSpecification(searchable);
		return findAll(spec,sort);
	}

	@Override
	public List<T> findList(Searchable searchable, com.landian.commons.jpa.order.Order... orders) {
		Sort sort = SortBuilderRef.build(orders);
		Specification<T> spec = buildSpecification(searchable);
		return findAll(spec,sort);
	}

	@Override
	public Page<T> findPage(List<Predicable> predicableList, Pageable pageable) {
		Predicable[] predicableArr = null;
		if(CollectionUtils.isNotEmpty(predicableList)){
			predicableArr = predicableList.toArray(new Predicable[]{});
		}
		return findPage(pageable,predicableArr);
	}

	@Override
	public Page<T> findPage(Searchable searchable, Pageable pageable) {
		return findPage(searchable,pageable,new Predicable[]{});
	}

	private Specification<T> buildSpecification(Predicable[] predicable) {
		return (root, query, cb) -> {
			Predicate[] predicates = PredicateFactory.build(root, cb, predicable);
			query.where(predicates);
			return null;
		};
	}

	private Specification<T> buildSpecification(Searchable searchVo, Predicable... predicable){
		Specification<T> spec = (root, query, cb) -> {
			Predicate[] predicates = PredicateFactory.build(root, cb, searchVo, predicable);
			query.where(predicates);
			return null;
		};
		return spec;
	}

	@Override
	public Page<T> findPage(Pageable pageable, Predicable... predicable) {
		Specification<T> spec = buildSpecification(predicable);
		return findAll(spec,pageable);
	}

	@Override
	public Page<T> findPage(Searchable searchable, Pageable pageable, Predicable... predicable) {
		Specification<T> spec = buildSpecification(searchable, predicable);
		return findAll(spec,pageable);
	}

	@Override
	public Long countByHQL(String hql) {
		return countByHQL(hql,null);
	}

	@Override
	public Long countByHQL(String hql, List<ParameterUnit> parameterUnitList) {
		Query query = entityManager.createQuery(hql);
		// 设置Parameter
		setParameter(parameterUnitList, query);
		Object result = query.getSingleResult();
		return (Long)result;
	}

	@Override
	public List<T> findByHQL(String hql) {
		Query query = entityManager.createQuery(hql);
		return query.getResultList();
	}

	@Override
	public Page<T> findByHQL(String hql, String countHQL, Pageable pageable) {
		return findByHQL(hql,countHQL,null,pageable);
	}

	@Override
	public List<T> findByHQL(String hql, List<ParameterUnit> parameterUnitList) {
		Query query = entityManager.createQuery(hql);
		// 设置Parameter
		setParameter(parameterUnitList, query);
		return query.getResultList();
	}

	@Override
	public Page<T> findByHQL(String hql, String countHQL, List<ParameterUnit> parameterUnitList, Pageable pageable) {
		Query query = entityManager.createQuery(hql);
		query.setFirstResult(pageable.getOffset());
		query.setMaxResults(pageable.getPageSize());
		// 设置Parameter
		setParameter(parameterUnitList, query);
		List<T> list = query.getResultList();
		Integer size = list.size();
		long total = size.longValue();
		if(size >= pageable.getPageSize()){
			total = countByHQL(countHQL,parameterUnitList);
		}
		return new PageImpl(list,pageable,total);
	}

	/**
	 * 设置Parameter
	 * @param parameterUnitList
	 * @param query
	 */
	private void setParameter(List<ParameterUnit> parameterUnitList, Query query) {
		if(CollectionUtils.isNotEmpty(parameterUnitList)){
			parameterUnitList.forEach(b -> query.setParameter(b.getName(), b.getValue()));
		}
	}

	private List<ParameterUnit> getParameterUnitList(ListHql listHql){
		List<QueryPart> queryPartList = listHql.getQueryPart();
		if(CollectionUtils.isEmpty(queryPartList)){
			return Collections.EMPTY_LIST;
		}
		return queryPartList.stream().map(b -> b.getParameterUnit()).collect(toList());
	}

	@Override
	public List<T> findByPathEqual(com.querydsl.core.types.Path<?> dslPath, Object value) {
		Predicable predicable = PredicableFactory.equal(dslPath, value);
		return findList(predicable);
	}

	@Override
	public List<T> findByPathEqual(com.querydsl.core.types.Path<?> dslPath, Object value, Sort sort) {
		Predicable predicable = PredicableFactory.equal(dslPath, value);
		return findList(predicable, sort);
	}

	@Override
	public List<T> findByPathEqual(com.querydsl.core.types.Path<?> dslPath, Object value,
								   com.landian.commons.jpa.order.Sort sort) {
		Predicable predicable = PredicableFactory.equal(dslPath, value);
		return findList(predicable, sort);
	}

	@Override
	public List<T> findByPathEqual(com.querydsl.core.types.Path<?> dslPath, Object value, OrderUnit orderUnit) {
		Predicable predicable = PredicableFactory.equal(dslPath, value);
		Sort sort = SortBuilder.build(orderUnit);
		return findList(predicable, sort);
	}

	@Override
	public List<T> findByPathEqual(com.querydsl.core.types.Path<?> dslPath, Object value,
								   com.landian.commons.jpa.order.Order order) {
		Predicable predicable = PredicableFactory.equal(dslPath, value);
		Sort sort = SortBuilderRef.build(order);
		return findList(predicable, sort);
	}

	@Override
	public List<T> findByPathIn(com.querydsl.core.types.Path<?> dslPath, Collection collection) {
		Predicable predicable = PredicableFactory.in(dslPath, collection);
		return findList(predicable);
	}

	@Override
	public List<T> findByPathIn(com.querydsl.core.types.Path<?> dslPath, Collection collection, Sort sort) {
		Predicable predicable = PredicableFactory.in(dslPath, collection);
		return findList(predicable, sort);
	}

	@Override
	public List<T> findByPathIn(com.querydsl.core.types.Path<?> dslPath, Collection collection,
								com.landian.commons.jpa.order.Order order) {
		Predicable predicable = PredicableFactory.in(dslPath, collection);
		return findList(predicable, order);
	}

	@Override
	public List<T> findByPathIn(com.querydsl.core.types.Path<?> dslPath, Collection collection,
								com.landian.commons.jpa.order.Sort sort) {
		Predicable predicable = PredicableFactory.in(dslPath, collection);
		return findList(predicable, sort);
	}

	@Override
	public List<T> findByHQL(ListHql listHql) {
		return findByHQL(listHql.selectHQL(), getParameterUnitList(listHql));
	}

	@Override
	public Page<T> findByHQL(PageHql pageHql, Pageable pageable) {
		return findByHQL(pageHql.selectHQL(),pageHql.countHQL(), getParameterUnitList(pageHql), pageable);
	}

	/**
	 * 通过EntityManager来完成查询
	 * @param sql
	 * @return
	 */
    @SuppressWarnings("unchecked")
	@Override
    public List<Object[]> listBySQL(String sql) {
        return entityManager.createNativeQuery(sql).getResultList();
    }

	@Override
	public List<Object[]> listByHQL(String hql) {
		return entityManager.createQuery(hql).getResultList();
	}

	@Override
	public <K> List<K> listByHQLAsSingleList(ListHqlContext listHqlContext, Class<K> clazz) {
		String hql = listHqlContext.getHql();
		Query query = entityManager.createQuery(hql);
		setParameter(listHqlContext.getParameterUnitList(), query);
		return query.getResultList();
	}

	@Override
	public <K> Optional<K> listByHQLAsSingleResult(ListHqlContext listHqlContext, Class<K> clazz) {
		String hql = listHqlContext.getHql();
		Query query = entityManager.createQuery(hql);
		setParameter(listHqlContext.getParameterUnitList(), query);
		List resultList = query.getResultList();
		Object object = null;
		if(CollectionUtils.isNotEmpty(resultList)){
			object = resultList.get(0);
		}
		return (Optional<K>) Optional.ofNullable(object);
	}

	@Override
	public List listField(com.querydsl.core.types.Path<?> dslPath) {
		OrderUnitContainer orderUnitContainer = OrderUnitContainer.newInstance();
    	return listField(dslPath, orderUnitContainer);
	}

	@Override
	public List listField(com.querydsl.core.types.Path<?> dslPath, OrderUnit... orderUnits) {
		OrderUnitContainer orderUnitContainer = OrderUnitContainer.newInstance().add(orderUnits);
		return listField(dslPath,orderUnitContainer);
	}

	@Override
	public List listField(com.querydsl.core.types.Path<?> dslPath, com.landian.commons.jpa.order.Order... orders) {
		com.landian.commons.jpa.order.Sort sort =
				com.landian.commons.jpa.order.Sort.newInstance().add(orders);
		return listField(dslPath,sort);
	}



	@Override
	public List listField(com.querydsl.core.types.Path<?> dslPath, Predicable... predicableArr) {
		PredicableContainer predicableContainer = PredicableContainer.newInstance().add(predicableArr);
		return listField(dslPath,predicableContainer);
	}

	@Override
	public List listField(com.querydsl.core.types.Path<?> dslPath, Predicable predicable, OrderUnit orderUnit) {
		PredicableContainer predicableContainer = PredicableContainer.newInstance().add(predicable);
		OrderUnitContainer orderUnitContainer = OrderUnitContainer.newInstance().add(orderUnit);
		return listField(dslPath,predicableContainer,orderUnitContainer);
	}

	@Override
	public List listField(com.querydsl.core.types.Path<?> dslPath, Predicable predicable,
						  com.landian.commons.jpa.order.Order order) {
		PredicableContainer predicableContainer = PredicableContainer.newInstance().add(predicable);
		com.landian.commons.jpa.order.Sort sort =
				com.landian.commons.jpa.order.Sort.newInstance().add(order);
		return listField(dslPath,predicableContainer,sort);
	}

	@Override
	public List listField(com.querydsl.core.types.Path<?> dslPath, OrderUnitContainer orderUnitContainer) {
		PredicableContainer predicableContainer = PredicableContainer.newInstance();
		return listField(dslPath,predicableContainer,orderUnitContainer);
	}

	@Override
	public List listField(com.querydsl.core.types.Path<?> dslPath, com.landian.commons.jpa.order.Sort sort) {
		PredicableContainer predicableContainer = PredicableContainer.newInstance();
		return listField(dslPath,predicableContainer,sort);
	}

	@Override
	public List listField(com.querydsl.core.types.Path<?> dslPath, PredicableContainer predicableContainer) {
		OrderUnitContainer orderUnitContainer = OrderUnitContainer.newInstance();
		return listField(dslPath,predicableContainer,orderUnitContainer);
	}

	@Override
	public List listField(com.querydsl.core.types.Path<?> dslPath, PredicableContainer predicableContainer, OrderUnitContainer orderUnitContainer) {
		List<Tuple> tupleList = listTuple(Lists.newArrayList(dslPath), predicableContainer, orderUnitContainer);
		if(CollectionUtils.isEmpty(tupleList)){
			return Collections.emptyList();
		}
		return tupleList.stream().map(tuple -> tuple.get(0)).collect(toList());
	}

	@Override
	public List listField(com.querydsl.core.types.Path<?> dslPath, PredicableContainer predicableContainer,
						  com.landian.commons.jpa.order.Sort sort) {
		List<Tuple> tupleList = listTuple(Lists.newArrayList(dslPath), predicableContainer, sort);
		if(CollectionUtils.isEmpty(tupleList)){
			return Collections.emptyList();
		}
		return tupleList.stream().map(tuple -> tuple.get(0)).collect(toList());
	}

	@Override
	public List<Tuple> listTuple(com.querydsl.core.types.Path<?>... pathArr){
    	if(null == pathArr || pathArr.length < 0){
    		return Collections.emptyList();
		}
		return listTuple(Lists.newArrayList(pathArr),
				PredicableContainer.newInstance(), OrderUnitContainer.newInstance());
	}

	@Override
	public List<Tuple> listTuple(List<com.querydsl.core.types.Path<?>> pathList, PredicableContainer predicableContainer, OrderUnitContainer orderUnitContainer){
    	if(CollectionUtils.isEmpty(pathList)){
    		return Collections.emptyList();
		}
		CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
		CriteriaQuery<Tuple> tupleQuery = criteriaBuilder.createTupleQuery();
		Root<?> root = tupleQuery.from(getDomainClass());
		List<Selection<?>> selectionList = pathList.stream().map(path -> root.get(PathUtils.getFieldName(path))).collect(toList());
		tupleQuery.multiselect(selectionList);
		// 添加查询条件
		where(root, criteriaBuilder, tupleQuery, predicableContainer);
		// 添加排序
		orderBy(root, criteriaBuilder, tupleQuery, orderUnitContainer);
		return entityManager.createQuery(tupleQuery).getResultList();
	}

	@Override
	public List<Tuple> listTuple(List<com.querydsl.core.types.Path<?>> pathList, PredicableContainer predicableContainer,
								 com.landian.commons.jpa.order.Sort sort){
		if(CollectionUtils.isEmpty(pathList)){
			return Collections.emptyList();
		}
		CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
		CriteriaQuery<Tuple> tupleQuery = criteriaBuilder.createTupleQuery();
		Root<?> root = tupleQuery.from(getDomainClass());
		List<Selection<?>> selectionList = pathList.stream().map(path -> root.get(PathUtils.getFieldName(path))).collect(toList());
		tupleQuery.multiselect(selectionList);
		// 添加查询条件
		where(root, criteriaBuilder, tupleQuery, predicableContainer);
		// 添加排序
		orderBy(root, criteriaBuilder, tupleQuery, sort);
		return entityManager.createQuery(tupleQuery).getResultList();
	}

	/**
	 * 添加查询条件
	 * @param root
	 * @param criteriaBuilder
	 * @param criteriaQuery
	 * @param predicableContainer
	 */
	private void where(Root<?> root, CriteriaBuilder criteriaBuilder, CriteriaQuery<?> criteriaQuery, PredicableContainer predicableContainer) {
		if(null != predicableContainer && CollectionUtils.isNotEmpty(predicableContainer.getList())){
			List<Predicate> predicateList = predicableContainer.getList().stream().map(b -> b.build(root, criteriaBuilder)).collect(toList());
			criteriaQuery.where(predicateList.toArray(new Predicate[]{}));
		}
	}

	/**
	 * 添加排序
	 * @param root
	 * @param criteriaBuilder
	 * @param criteriaQuery
	 * @param orderUnitContainer
	 */
	private void orderBy(Root<?> root, CriteriaBuilder criteriaBuilder, CriteriaQuery<?> criteriaQuery, OrderUnitContainer orderUnitContainer) {
		if(null != orderUnitContainer && CollectionUtils.isNotEmpty(orderUnitContainer.getList())){
			List<Order> orderList = orderUnitContainer.getList().stream().map(orderUnit -> {
				String fieldOrder = PathUtils.getFieldName(orderUnit.getPath());
				Path<Object> orderPath = root.get(fieldOrder);
				if (Sort.Direction.ASC == orderUnit.getDirection()) {
					return criteriaBuilder.asc(orderPath);
				} else {
					return criteriaBuilder.desc(orderPath);
				}
			}).collect(toList());
			criteriaQuery.orderBy(orderList);
		}
	}

	/**
	 * 添加排序
	 * @param root
	 * @param criteriaBuilder
	 * @param criteriaQuery
	 * @param sort
	 */
	private void orderBy(Root<?> root, CriteriaBuilder criteriaBuilder, CriteriaQuery<?> criteriaQuery,
						 com.landian.commons.jpa.order.Sort sort) {
		if(null != sort && CollectionUtils.isNotEmpty(sort.getList())){
			List<Order> orderList = sort.getList().stream().map(order -> {
				String fieldOrder = PathUtils.getFieldName(order.getPath());
				Path<Object> orderPath = root.get(fieldOrder);
				if (Sort.Direction.ASC == order.getDirection()) {
					return criteriaBuilder.asc(orderPath);
				} else {
					return criteriaBuilder.desc(orderPath);
				}
			}).collect(toList());
			criteriaQuery.orderBy(orderList);
		}
	}

	@Override
	public List hqlAsSingleList(String hql) {
		return listByHQL(hql);
	}

	@Override
	public void updateBySql(String sql, Object...args) {
    	Query query = entityManager.createNativeQuery(sql);
    	int i = 0;
    	for(Object arg:args) {
    		query.setParameter(++i,arg);
    	}
    	query.executeUpdate();
	}

	@Override
	public void updateByHql(String hql, Object...args) {
    	Query query = entityManager.createQuery(hql);
    	int i = 0;
    	for(Object arg:args) {
    		System.out.println(arg);
    		query.setParameter(++i,arg);
    	}
    	query.executeUpdate();
	}

	@Override
	public int update(String id, com.querydsl.core.types.Path<?> idPath,
					  com.querydsl.core.types.Path<?> updatePath, Object value) {
		UpdateUnit updateUnit = UpdateUnit.newInstance(updatePath, value);
		return update(id, idPath, updateUnit);
	}

	/**
	 * TODO 有没有其它方法获取到模型的ID属性信息，可参考
	 * org.springframework.data.jpa.repository.support.SimpleJpaRepository#exists(java.io.Serializable)#entityInformation.getIdAttributeNames()
	 * entityManager.getMetamodel()
	 * @param id
	 * @param idPath
	 * @param updateUnits
	 * @return
	 */
	@Override
	public int update(String id, com.querydsl.core.types.Path<?> idPath, UpdateUnit... updateUnits){
		UpdateUnitContainer updateUnitContainer = UpdateUnitContainer.newInstance().add(updateUnits);
		return updateById(id, idPath, updateUnitContainer);
	}

	@Override
	public int update(String id, com.querydsl.core.types.Path<?> idPath, UpdateUnitContainer updateUnitContainer) {
		return updateById(id, idPath, updateUnitContainer);
	}

	@Override
	public int update(UpdateUnit updateUnit, Predicable... predicableArr) {
		if(null == updateUnit){
			throw new RuntimeException("UpdateUnit can not be null!");
		}
		List<Predicable> predicableList = PredicableConverter.asList(predicableArr);
		if(CollectionUtils.isEmpty(predicableList)){
			throw new RuntimeException("Predicable can not be null!");
		}
		CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
		CriteriaUpdate criteriaUpdate = criteriaBuilder.createCriteriaUpdate(getDomainClass());
		Root root = criteriaUpdate.from(getDomainClass());
		// 添加条件
		predicableList.stream().forEach(predicable -> criteriaUpdate.where(predicable.build(root, criteriaBuilder)));
		String fieldName = PathUtils.getFieldName(updateUnit.getPath());
		Path fieldPathTarget = root.get(fieldName);
		criteriaUpdate.set(fieldPathTarget, updateUnit.getValue());
		Query query = entityManager.createQuery(criteriaUpdate);
		return query.executeUpdate();
	}

	/**
	 * update
	 * @param id
	 * @param idPath
	 * @param updateUnitContainer
	 * @return
	 */
	private int updateById(String id, com.querydsl.core.types.Path<?> idPath, UpdateUnitContainer updateUnitContainer) {
		List<UpdateUnit> updateUnitList = updateUnitContainer.getList();
		if(CollectionUtils.isEmpty(updateUnitList)){
			throw new RuntimeException("UpdateUnit can not be null!");
		}
		CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
		CriteriaUpdate criteriaUpdate = criteriaBuilder.createCriteriaUpdate(getDomainClass());
		String idName = PathUtils.getFieldName(idPath);
		Root root = criteriaUpdate.from(getDomainClass());
		Path idPathTarget = root.get(idName);
		Predicate predicateId = getIdPredicate(criteriaBuilder, id, idPathTarget);
		criteriaUpdate.where(predicateId);
		updateUnitList.stream().filter(updateUnit -> null != updateUnit).forEach(updateUnit -> {
			String fieldName = PathUtils.getFieldName(updateUnit.getPath());
			Path fieldPathTarget = root.get(fieldName);
			criteriaUpdate.set(fieldPathTarget, updateUnit.getValue());
		});
		Query query = entityManager.createQuery(criteriaUpdate);
		return query.executeUpdate();
	}

	/**
	 *
	 * @param predicableArr
	 * @return
	 */
	@Override
	public int delete(Predicable... predicableArr){
		List<Predicable> predicableList = PredicableConverter.asList(predicableArr);
		if(CollectionUtils.isEmpty(predicableList)){
			throw new RuntimeException("Predicate can not be null!");
		}
		CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
		CriteriaDelete<T> criteriaDelete = criteriaBuilder.createCriteriaDelete(getDomainClass());
		Root root = criteriaDelete.from(getDomainClass());
		predicableList.forEach(predicable -> criteriaDelete.where(predicable.build(root, criteriaBuilder)));
		Query query = entityManager.createQuery(criteriaDelete);
		return query.executeUpdate();
	}

}
